from typing import Dict, Any
from enum import Enum


class Directory:
    field_names = [
        "newNonce",
        "newAccount",
        "newOrder",
        "newAuthz",
        "revokeCert",
        "keyChange",
    ]

    class Meta:
        fields_names = [
            "termsOfService",
            "website",
            "caaIdentities",
            "externalAccountRequired",
        ]

        def __init__(self, meta_info: Dict[str, Any]):
            self._meta_info = {}
            for name in Directory.Meta.fields_names:
                if name in meta_info:
                    self._meta_info[name] = meta_info[name]

        def __getattr__(self, name: str):
            try:
                return self[name]
            except KeyError as e:
                raise AttributeError(str(e))

        def __getitem__(self, name: str):
            try:
                return self._meta_info[name]
            except KeyError:
                raise KeyError(f"{name} field not found in Directory.Meta")

    def __init__(self, urls: Dict[str, Any]):
        self._urls = {}
        if "meta" in urls:
            self._urls["meta"] = Directory.Meta(urls["meta"])
        for name in Directory.field_names:
            if name in urls:
                self._urls[name] = urls[name]

    def __getattr__(self, name: str):
        try:
            return self[name]
        except KeyError as e:
            raise AttributeError(str(e))

    def __getitem__(self, name: str):
        try:
            return self._urls[name]
        except KeyError:
            raise KeyError(f"{name} field not found in Directory")


class Account:
    field_names = [
        "status",
        "contact",
        "termsOfServiceAgreed",
        "externalAccountBinding",
        "orders",
    ]

    class Status(Enum):
        VALID = "valid"
        DEACTIVATED = "deactivated"
        REVOKED = "revoked"

    def __init__(self, account_info: Dict[str, Any], account_location: str):
        self._account_info = {}
        self._account_url = account_location
        if "status" not in account_info:
            raise ValueError("status is required for Account")
        for name in Account.field_names:
            if name in account_info:
                self._account_info[name] = account_info[name]
        self._account_info["status"] = Account.Status(self._account_info["status"])

    @property
    def account_url(self):
        return self._account_url

    def __getattr__(self, name: str):
        try:
            return self[name]
        except KeyError as e:
            raise AttributeError(str(e))

    def __getitem__(self, name: str):
        try:
            return self._account_info[name]
        except KeyError:
            raise KeyError(f"{name} field not found in Account")


class Order:
    field_names = [
        "status",
        "expires",
        "identifiers",
        "authorizations",
        "finalize",
        "certificate",
        "notBefore",
        "notAfter",
        "error",
    ]

    class Status(Enum):
        PENDING = "pending"
        READY = "ready"
        PROCESSING = "processing"
        VALID = "valid"
        INVALID = "invalid"

    def __init__(self, order_info: Dict[str, Any], order_location: str):
        self._order_info = {}
        self._order_url = order_location
        if "status" not in order_info:
            raise ValueError("status is required for Order")
        for name in Order.field_names:
            if name in order_info:
                self._order_info[name] = order_info[name]
        self._order_info["status"] = Order.Status(self._order_info["status"])

    @property
    def order_url(self):
        return self._order_url

    def __getattr__(self, name: str):
        try:
            return self[name]
        except KeyError as e:
            raise AttributeError(str(e))

    def __getitem__(self, name: str):
        try:
            return self._order_info[name]
        except KeyError:
            raise KeyError(f"{name} field not found in Order")


class Authorization:
    field_names = ["identifier", "status", "expires", "challenges", "wildcard"]

    class Status(Enum):
        PENDING = "pending"
        VALID = "valid"
        INVALID = "invalid"
        DEACTIVATED = "deactivated"
        EXPIRED = "expired"
        REVOKED = "revoked"

    def __init__(self, authorization_info: Dict[str, Any]):
        self._authorization_info = {}
        if "status" not in authorization_info:
            raise ValueError("status is required for Authorization")
        for name in Authorization.field_names:
            if name in authorization_info:
                self._authorization_info[name] = authorization_info[name]
        # 特殊处理status
        self._authorization_info["status"] = Authorization.Status(
            self._authorization_info["status"]
        )
        # 特殊处理challenges
        self._authorization_info["challenges"] = [
            Challenge(chall) for chall in self._authorization_info["challenges"]
        ]

    def __getattr__(self, name: str):
        try:
            return self[name]
        except KeyError as e:
            raise AttributeError(str(e))

    def __getitem__(self, name: str):
        try:
            return self._authorization_info[name]
        except KeyError:
            raise KeyError(f"{name} field not found in Authorization")


class Challenge:
    field_names = ["type", "url", "status", "validated", "error", "token"]

    class Status(Enum):
        PENDING = "pending"
        PROCESSING = "processing"
        VALID = "valid"
        INVALID = "invalid"

    def __init__(self, challenge_info: Dict[str, Any]):
        self._challenge_info = {}
        if "status" not in challenge_info:
            raise ValueError("status is required for Challenge")
        for name in Challenge.field_names:
            if name in challenge_info:
                self._challenge_info[name] = challenge_info[name]
        self._challenge_info["status"] = Challenge.Status(
            self._challenge_info["status"]
        )

    def __getattr__(self, name: str):
        try:
            return self[name]
        except KeyError as e:
            raise AttributeError(str(e))

    def __getitem__(self, name: str):
        try:
            return self._challenge_info[name]
        except KeyError:
            raise KeyError(f"{name} field not found in Challenge")
